//
//  UIViewController+runtimeCheck.m
//  FCTools
//
//  Created by WJC on 2018/10/25.
//  Copyright © 2018 wjc. All rights reserved.
//

#import "UIViewController+runtimeCheck.h"
#import <objc/runtime.h>
#import "NSObject+KVCChangeType.h"
#import "WJCDefine.h"
@implementation UIViewController (runtimeCheck)
/**
 检测对象是否存在该属性
 
 @param instance 控制器对象
 @param verifyPropertyName 控制器属性值
 @return 是否存在
 */
- (BOOL)checkIsExistPropertyWithInstance:(id)instance verifyPropertyName:(NSString *)verifyPropertyName andLogAllProperty:(BOOL)log
{
    unsigned int outCount, i;
        // 获取对象里的属性列表
    objc_property_t * properties = class_copyPropertyList([instance
                                                           class], &outCount);
    
    if(log){
        for (i = 0; i < outCount; i++) {
            objc_property_t property =properties[i];
                //  属性名转成字符串
            NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
           
            if(log){
                NSLog(@"控制器拥有的成员属性名字为 %@ ",propertyName);
            }
        }
    }
    for (i = 0; i < outCount; i++) {
        objc_property_t property =properties[i];
            //  属性名转成字符串
        NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
            // 判断该属性是否存在
        if ([propertyName isEqualToString:verifyPropertyName]) {
            free(properties);
            return YES;
        }
    }
    free(properties);
    return NO;
}
/**
 获取相应的控制器属性的对应类型
 
 @param controller 控制器
 @param verifyPropertyName 类型值
 @return 类型char
 */
-(const char*)getControllerIvalWithController:(id)controller andPropertyName:(NSString *)verifyPropertyName{
    const char *method="";
    const char *PropertyName = [[NSString stringWithFormat:@"_%@",verifyPropertyName] cStringUsingEncoding:NSASCIIStringEncoding];
    unsigned int methodCount = 0;
    Ivar * ivars = class_copyIvarList([controller class], &methodCount);
    for (unsigned int i = 0; i < methodCount; i ++) {
        Ivar ivar = ivars[i];
        const char * name = ivar_getName(ivar);
        const char * type = ivar_getTypeEncoding(ivar);
        if (strcmp(PropertyName, name) == 0) {
                //            NSMutableString *str=;
            method=[[[[NSMutableString stringWithFormat:@"%s",type] stringByReplacingOccurrencesOfString:@"\"" withString:@""] stringByReplacingOccurrencesOfString:@"@" withString:@""] cStringUsingEncoding:NSASCIIStringEncoding];
            break;
        }
        
    }
    free(ivars);
    return method;
}
- (BOOL)checkIsExistMethodWithInstance:(id)instance verifyMethodName:(NSString *)verifyMethodName{
        //调用公共变量
        //    SEL sel = NSSelectorFromString(@"shareAlert");
        //    if ([self respondsToSelector:sel]) {
        //        [self performSelector:sel];
        //    }
        //    WJCLog(@"//控制器是否存在方法:%ld",[super checkIsExistPropertyWithverifyPropertyName:@"urlString"]);
        //先获取类名
    NSString *className = NSStringFromClass([instance class]);
    const char *cClassName = [className UTF8String];
    
    id theClass = objc_getClass(cClassName);
        //用来计数
    unsigned int outCount;
    
    Method *m =  class_copyMethodList(theClass,&outCount);
    BOOL isGet=NO;
    for (int i = 0; i<outCount; i++) {
        SEL a = method_getName(*(m+i));
        NSString *sn = NSStringFromSelector(a);
        if ([sn isEqualToString:verifyMethodName]) {
                //            [self performSelector:a];
            isGet=YES;
            break;
        }
    }
    return isGet;
}
/**
 方法交换
 
 @param funcClass 被交换的对象类
 @param method 被交换的方法
 @param ControllerClass 交换的对象
 @param ChangeMethod 交换的方法
 */
-(void)changeMethodWithFuncClass:(Class)funcClass andMethod:(SEL)method andChangeControllerClass:(Class)ControllerClass andChangeMethod:(SEL)ChangeMethod{
    Method FCMethod=class_getInstanceMethod(funcClass, method);
    Method FCReplace=class_getInstanceMethod(ControllerClass, ChangeMethod);
    method_exchangeImplementations(FCMethod, FCReplace);
}



/**
 rt控制器跳转

 @param name 控制器名
 @param objectData 控制器属性值
 */
-(UIViewController *)pushAppControllerWithControllerName:(NSString*)name andObjectData:(NSDictionary*)objectData andTitle:(NSString*)title{
    const char *className = [name cStringUsingEncoding:NSASCIIStringEncoding];
        // 从一个字串返回一个类
    Class newClass = objc_getClass(className);
    if (!newClass)
        {
//         [SVProgressHUD showErrorWithStatus:@"暂不支持或找不到相应信息"];
            NSLog(@"控制其名称'%@'找不到",name);
            [self pushAppControllerWithControllerName:@"ErrorFindTableViewController" andObjectData:name?@{@"errorControllerName":name}:nil andTitle:nil];
        return nil;
        }
    if (objectData) {
            // 创建对象
        id instance = [[newClass alloc] init];
            // 对该对象赋值属性
        NSDictionary * propertys = objectData;
        [propertys enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
                // 检测这个对象是否存在该属性
            WJCWeakSelf
            if ([self checkIsExistPropertyWithInstance:instance verifyPropertyName:key andLogAllProperty:NO]||[self checkIsExistPropertyWithInstance:newClass.superclass verifyPropertyName:key andLogAllProperty:NO]) {
                if([obj isKindOfClass:[NSDictionary class]]){
                    const char *objName = [weakSelf getControllerIvalWithController:instance andPropertyName:key];
                    NSString *objNameStr=[NSString stringWithFormat:@"%s",objName];
                    if(objNameStr.length>0&&!([objNameStr isEqual:@"NSMutableDictionary"]||[objNameStr isEqual:@"NSDictionary"])){
                        Class newClass = objc_getClass(objName);
                        
                        id object=[[newClass alloc] init];
                        [object setKVCWithObj:obj];
                        [instance setValue:object forKey:key];
                    }else{
                        [instance setValue:obj forKey:key];
                    }
                }else  if([obj isKindOfClass:[NSArray class]]){
                    const char *objName = [weakSelf getControllerIvalWithController:instance andPropertyName:key];
                    NSString *objNameStr=[NSString stringWithFormat:@"%s",objName];
                    if(objNameStr.length>0&&!([objNameStr isEqual:@"NSMutableArray"]||[objNameStr isEqual:@"NSArray"])){
                        Class newClass = objc_getClass(objName);
                        id object=[[newClass alloc] init];
                        [object setKVCWithObj:obj];
                        [instance setValue:object forKey:key];
                    }else{
                        [instance setValue:obj forKey:key];
                    }
                }
                    // 利用kvc赋值
                else{
                    [instance setValue:obj forKey:key];
                }
            }
        }];
            // 跳转到对应的控制器
        if (title) {
            ((UIViewController*)instance).title=title;
        }
//        [self debugClass:[instance class] PropertysWithDictionary:objectData];
        [self.navigationController pushViewController:instance animated:YES];
        return instance;
    }else{
        id instance = [[newClass alloc] init];
        if (title) {
            ((UIViewController*)instance).title=title;
        }
        [self.navigationController pushViewController:instance animated:YES];
        return instance;
    }
}
//-(UIViewController *)pushAppControllerWithControllerName:(NSString *)name andURL:(NSString *)url andModelStr:(NSString *)modelString andTitle:(NSString *)title{
//    
//}
-(id)initWithObjectName:(NSString *)name andObjectData:(NSDictionary *)objectData{
    const char *className = [name cStringUsingEncoding:NSASCIIStringEncoding];
        // 从一个字串返回一个类
    Class newClass = objc_getClass(className);
    if (!newClass)
        {
//        [SVProgressHUD showErrorWithStatus: @"找不到对象"];
        return nil;
        }
     id instance = [[newClass alloc] init];
    if (objectData) {
            // 创建对象
       
            // 对该对象赋值属性
        NSDictionary * propertys = objectData;
        [propertys enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
                // 检测这个对象是否存在该属性
            WJCWeakSelf
            if ([self checkIsExistPropertyWithInstance:instance verifyPropertyName:key andLogAllProperty:NO]) {
                if([obj isKindOfClass:[NSDictionary class]]){
                    const char *objName = [weakSelf getControllerIvalWithController:instance andPropertyName:key];
                    NSString *objNameStr=[NSString stringWithFormat:@"%s",objName];
                    if(objNameStr.length>0&&!([objNameStr isEqual:@"NSMutableDictionary"]||[objNameStr isEqual:@"NSDictionary"])){
                        Class newClass = objc_getClass(objName);
                        
                        id object=[[newClass alloc] init];
                        [object setKVCWithObj:obj];
                        [instance setValue:object forKey:key];
                    }else{
                        [instance setValue:obj forKey:key];
                    }
                }else  if([obj isKindOfClass:[NSArray class]]){
                    const char *objName = [weakSelf getControllerIvalWithController:instance andPropertyName:key];
                    NSString *objNameStr=[NSString stringWithFormat:@"%s",objName];
                    if(objNameStr.length>0&&!([objNameStr isEqual:@"NSMutableArray"]||[objNameStr isEqual:@"NSArray"])){
                        Class newClass = objc_getClass(objName);
                        id object=[[newClass alloc] init];
                        [object setKVCWithObj:obj];
                        [instance setValue:object forKey:key];
                    }else{
                        [instance setValue:obj forKey:key];
                    }
                }
                    // 利用kvc赋值
                else{
                    [instance setValue:obj forKey:key];
                }
            }
            
                
                
        }];
        return instance;
    }
    return instance;
}


-(id)getObjectWithOjbect:(Class)Ojbect andName:(NSString*)name{
    NSString *className = NSStringFromClass(Ojbect);
    const char *cClassName = [className UTF8String];
    
    id theClass = objc_getClass(cClassName);
        //用来计数
    unsigned int outCount;
    
    Method *m =  class_copyMethodList(theClass,&outCount);
    BOOL isGet=NO;
    for (int i = 0; i<outCount; i++) {
        SEL a = method_getName(*(m+i));
        NSString *sn = NSStringFromSelector(a);
        if ([sn isEqualToString:name]) {
          return [Ojbect performSelector:a];
            isGet=YES;
        }
    }

    return nil;
}
/**
 调用方法传入多参数
 
 @param Ojbect 方法所在控制器
 @param method 方法名
 @param object 参数
 // 调用方法三
 [self perform:@"testDemo:withSeconde:withThree:" withObjects:@"first",@"sercond",@"three",nil];
 */
- (id)performObjbect:(Class)Ojbect andMethod:(NSString *)method withObjects:(id)object,... {
    NSString *className = NSStringFromClass(Ojbect);
    const char *cClassName = [className UTF8String];
     id t = [[Ojbect alloc] init];
        // 获取方法签名
    NSMethodSignature *signature = [[Ojbect class] instanceMethodSignatureForSelector:NSSelectorFromString(method)];
    if (signature == nil) {
            //可以抛出异常也可以不操作。
        return nil;
    }
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
        // 设置调用者
    invocation.target = t;
        // 设置调用的方法
    invocation.selector = NSSelectorFromString(method);
        // 计算方法个数
    NSInteger paramsCount = signature.numberOfArguments - 2;
        //1.定义一个指向个数可变的参数列表指针；
    va_list args;
    
        //2.va_start(args, str);string为第一个参数，也就是最右边的已知参数,这里就是获取第一个可选参数的地址.使参数列表指针指向函数参数列表中的第一个可选参数，函数参数列表中参数在内存中的顺序与函数声明时的顺序是一致的。
    va_start(args, object);
    
    @try {
        if (object)
            {
                //依次取得除第一个参数以外的参数
                //4.va_arg(args,NSString)：返回参数列表中指针所指的参数，返回类型为NSString，并使参数指针指向参数列表中下一个参数。
            int i = 0;
                // 设置第一个参数
            [invocation setArgument:&object atIndex: i + 2];
            WJCLog(@"ss %@",object);
            id ss = va_arg(args, id);
            while (ss)
                {
                i ++;
                if (i >= paramsCount) {
                    break;
                }
                    // 设置除第一个以外的参数
                WJCLog(@"ss %@",ss);
                [invocation setArgument:&ss atIndex: i + 2];
                ss = va_arg(args,  id);
                }
            }
    } @catch (NSException *exception) {
        WJCLog(exception);
//        [SVProgressHUD showErrorWithStatus:[NSString stringWithFormat:@"发送错误%@",exception]];
    } @finally {
        
    }
        // NSInvocation : 利用一个NSInvocation对象包装一次方法调用（方法调用者、方法名、方法参数、方法返回值）
    
        //5.清空参数列表，并置参数指针args无效。
    va_end(args);
    
        //retain 所有参数，防止参数被释放dealloc
    [invocation retainArguments];
        // 调用方法
    [invocation invoke];
    
        //获得返回值类型
    const char *returnType = signature.methodReturnType;
        //声明返回值变量
    id returnValue;
        //如果没有返回值，也就是消息声明为void，那么returnValue=nil
    if( !strcmp(returnType, @encode(void)) ){
        returnValue =  nil;
    }else if( !strcmp(returnType, @encode(id)) ){
            //如果返回值为对象，那么为变量赋值
        [invocation getReturnValue:&returnValue];
    } else{
            //如果返回值为普通类型NSInteger  BOOL
            //返回值长度
        NSUInteger length = [signature methodReturnLength];
            //根据长度申请内存
        void *buffer = (void *)malloc(length);
            //为变量赋值
        [invocation getReturnValue:buffer];
        if( !strcmp(returnType, @encode(BOOL)) ) {
            returnValue = [NSNumber numberWithBool:*((BOOL*)buffer)];
        }
        else if( !strcmp(returnType, @encode(NSInteger)) ){
            returnValue = [NSNumber numberWithInteger:*((NSInteger*)buffer)];
        } else {
            returnValue = [NSValue valueWithBytes:buffer objCType:returnType];
        }
    }
    WJCLog(@"result:%@",returnValue);
    return returnValue;
}
//- (void)setCallBlock:(id)callBlock
//{
//    objc_setAssociatedObject(self, @selector(callBlock), callBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
//}
//
//- (id )callBlock
//{
//    return objc_getAssociatedObject(self, _cmd);
//        //    return objc_getAssociatedObject(self, @selector(callBlock));
//}
//- (void)debugClass:(Class)cls PropertysWithDictionary:(NSMutableDictionary *)dic
//{
//    if (![NSStringFromClass(cls.superclass) isEqualToString:NSStringFromClass([self class])]) {
//        uint count;
//        objc_property_t *properties = class_copyPropertyList(cls.superclass, &count);
//        for (int i = 0; i<count; i++) {
//            objc_property_t property = properties[i];
//            NSString *name = @(property_getName(property));
//            id value = [self valueForKey:name]?:@"nil";
//            [dic setObject:value forKey:name];// 注意使用self得到value
//        }
//        free(properties);
//        [self debugClass:(cls.superclass) PropertysWithDictionary:dic];
//    }
//}

@end
